#ifndef VFS_H_
#define VFS_H_

/*
	Copyright (C) 2011 Salil Bhagurkar

	This file is part of illusion

	illusion is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	illusion is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with illusion.
	If not, see <http://www.gnu.org/licenses/>.
*/

#include <kernel/types.h>
#include <kernel/glist.h>

//VFS node states when called vfs_open
#define STATE_CLOSED 0
#define STATE_READ 1
#define STATE_WRITE 2

#define STATE_MAX 2


//The following flags apply to both a VFS page as well as a vFS node
//When they apply to a VFS node, only the top level vfs_node information
//will be synced
//If both of the bits below are not set then the copy is synced.
#define VFS_SYNC_MEM (1 << 0) //The memory copy is new
#define VFS_SYNC_DEV (1 << 1) //The device copy is new
#define VFS_SYNC_CREATE (1 << 2) //This thing has been newly created (either in memory or on the device)
#define VFS_SYNC_DELETE (1 << 3) //There is a pending delete operation (either in memory or on the device)
#define VFS_SYNC_TRUNCATE (1 << 4) //All data pages must be removed by the sync provider

#define VFS_SYNC_TYPE_PAGE (1 << 4)
#define VFS_SYNC_TYPE_NODE (1 << 5)

#define VFS_SYNC_MASK 0x3f

#define VFS_IS_ROOT (1 << 6)

//Short page name to define where the data is going
#define VFS_STREAM_NAME_LEN 8

struct vfs_page {
	char stream[VFS_STREAM_NAME_LEN];
	u32 flags;
	uint_t start, length;
	void *page_data;
	struct vfs_page *next, *prev;
};


#define VFS_NAME_LEN 256
struct vfs_provider;

struct vfs_node {
	u32 flags;
	//The name of this VFS node
	char name[VFS_NAME_LEN];
	uint_t length;
	//The below two members are used by the open / close API
	uint_t state, reference;
	//The pages that define the data on this node.
	struct vfs_page *pages, *pages_tail;
	uint_t child_count;
	//The hierarchy
	struct vfs_node *parent, *child, *child_tail;
	struct vfs_node *next, *prev;
	//The device to which this vfs_node belongs
	struct vfs_device *dev;

	//A file system specific control structure
	//for the file system to identify this vfs_node on the disk.
	//This may contain for example a cluster number that identifies
	//the location of a node on disk
	void *class;
};

#define VFS_SP_NAME_LEN 32

//Do not cache data
#define VFS_SP_NOPAGECACHE (1 << 1)
//Do not cache node information once it is retrieved
#define VFS_SP_NONODECACHE (1 << 2)

struct vfs_sync_provider {
	u32 flags;
	char name[VFS_SP_NAME_LEN];
	char *supported_page_streams;
	//Synchronize the name and other top level info, and
	//all the data pages based on page names
	int (*sync_node)(struct vfs_node *this);
	int (*sync_page)(struct vfs_node *this, struct vfs_page *page);
	//Read in all the children that match the provided pattern
	//This will return a list of vfs_nodes. It will not plug in the
	//vfs_nodes to the main list. Plugging into the main list is at
	//the discretion of the VFS

	struct vfs_node *(*get_child)(struct vfs_node *parent);
	//Return the first child of the parent. This will be called if the VFS
	//does not already have any children. Can return null if there are no
	//children.

	struct vfs_node *(*next_child)(struct vfs_node *child);
	//Return the next child of a vfs_node. This will be called to get any
	//children. Can return null if the last child was reached.

	//TODO Allow sync provider to directly support read/write to bypass the VFS caching
};


#define VFS_DEV_NAME_LEN 32

struct vfs_device {
	char name[VFS_DEV_NAME_LEN];
	uint_t rw_unit;				//The size of one read/write unit (This is one for normal files, and may be 512 for block devices)
	struct vfs_node *root;
	struct vfs_sync_provider *provider;
	struct vfs_device *next, *prev;
	void *class;				//This will point to the control structure for the entity that manages this device
	uint_t deleted_count;
	struct vfs_node *deleted, *deleted_tail;	//When a node is deleted, it is attached here, waiting to be synced with the device
};

//The global device list
extern struct vfs_device *devs, *devs_tail;

int vfs_set_sync_provider(struct vfs_device *dev, struct vfs_sync_provider *prov);
int vfs_remove_sync_provider(struct vfs_device *dev);

struct vfs_node *vfs_create_raw_node(struct vfs_node *parent, char *name);

struct vfs_device *vfs_create_device(char *name, uint_t rw_unit);
int vfs_remove_device(char *name, bool force_dispose);
struct vfs_device *vfs_get_device(char *name);

struct vfs_node *vfs_create(struct vfs_node *parent, char *name);

int vfs_delete(struct vfs_node *node);

int vfs_sync_dev_deletes(struct vfs_node *ref_node);

int vfs_sync(struct vfs_node *node);

int vfs_sync_node(struct vfs_node *node);

int vfs_sync_page(struct vfs_node *node, struct vfs_page *page);

int vfs_dispose_node(struct vfs_node *node, bool force);


int vfs_get(struct vfs_node **result, struct vfs_node *from, char *path);

char *vfs_get_path(char *dst, unsigned dst_len, struct vfs_node *node);

struct vfs_node *vfs_get_child(struct vfs_node *node);

struct vfs_node *vfs_get_parent(struct vfs_node *node);

struct vfs_node *vfs_next_child(struct vfs_node *node);

int vfs_read(struct vfs_node *node, char *stream,
		void *buf, uint_t start, uint_t count);
int vfs_write(struct vfs_node *node, char *stream,
		void *buf, uint_t start, uint_t count);

int vfs_open(struct vfs_node *node, uint_t state);
int vfs_close(struct vfs_node *node, uint_t state);

int vfs_rename(struct vfs_node *node, char *new_name);

void debug_vfs_node(struct vfs_node *node);

#endif /* VFS_H_ */
